﻿
// <copyright file="AbstractListDecorator.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The abstract list decorator.
// </summary>


namespace SubhadraSolutions.Sharp.Utils.Collections.Generic
{
    using System;
    using System.Collections;
    using System.Collections.Generic;

    using SubhadraSolutions.Sharp.Utils.Validation;

    /// <summary>
    /// The abstract list decorator.
    /// </summary>
    /// <typeparam name="T">
    /// </typeparam>
    public abstract class AbstractListDecorator<T> : AbstractCollectionDecorator<T>, IList<T>, IList
    {
        /// <summary>
        /// The adapted list
        /// </summary>
        private readonly IList<T> adaptedList;

        /// <summary>
        /// Initializes a new instance of the <see cref="AbstractListDecorator{T}"/> class.
        /// </summary>
        /// <param name="adaptedList">
        /// The adapted list.
        /// </param>
        protected AbstractListDecorator(IList<T> adaptedList)
            : base(adaptedList)
        {
            Guard.ArgumentNotNull(adaptedList, "adaptedList");
            this.adaptedList = adaptedList;
        }

        /// <summary>
        /// Gets the adapted list.
        /// </summary>
        /// <value>
        /// The adapted list.
        /// </value>
        protected IList<T> AdaptedList
        {
            get
            {
                return this.adaptedList;
            }
        }

        /// <summary>
        /// Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1"/>.
        /// </summary>
        /// <param name="item">
        /// The object to locate in the <see cref="T:System.Collections.Generic.IList`1"/>.
        /// </param>
        /// <returns>
        /// The index of <paramref name="item"/> if found in the list; otherwise, -1.
        /// </returns>
        public virtual int IndexOf(T item)
        {
            return this.adaptedList.IndexOf(item);
        }

        /// <summary>
        /// Inserts an item to the <see cref="T:System.Collections.Generic.IList`1"/> at the specified index.
        /// </summary>
        /// <param name="index">
        /// The zero-based index at which <paramref name="item"/> should be inserted.
        /// </param>
        /// <param name="item">
        /// The object to insert into the <see cref="T:System.Collections.Generic.IList`1"/>.
        /// </param>
        public virtual void Insert(int index, T item)
        {
            this.adaptedList.Insert(index, item);
        }

        /// <summary>
        /// Removes the <see cref="T:System.Collections.Generic.IList`1"/> item at the specified index.
        /// </summary>
        /// <param name="index">
        /// The zero-based index of the item to remove.
        /// </param>
        public virtual void RemoveAt(int index)
        {
            this.adaptedList.RemoveAt(index);
        }

        /// <summary>
        /// Gets or sets the element at the specified index.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <returns>
        /// The <see cref="T"/>.
        /// </returns>
        public virtual T this[int index]
        {
            get
            {
                return this.adaptedList[index];
            }

            set
            {
                this.adaptedList[index] = value;
            }
        }

        #region IList Members

        /// <summary>
        /// Adds an item to the <see cref="T:System.Collections.IList"/>.
        /// </summary>
        /// <param name="value">
        /// The object to add to the <see cref="T:System.Collections.IList"/>.
        /// </param>
        /// <returns>
        /// The position into which the new element was inserted, or -1 to indicate that the item was not inserted into the collection,
        /// </returns>
        int IList.Add(object value)
        {
            this.Add((T)value);
            return this.Count - 1;
        }

        /// <summary>
        /// Clears this instance.
        /// </summary>
        void IList.Clear()
        {
            this.Clear();
        }

        /// <summary>
        /// Determines whether the <see cref="T:System.Collections.IList"/> contains a specific value.
        /// </summary>
        /// <param name="value">
        /// The object to locate in the <see cref="T:System.Collections.IList"/>.
        /// </param>
        /// <returns>
        /// true if the <see cref="T:System.Object"/> is found in the <see cref="T:System.Collections.IList"/>; otherwise, false.
        /// </returns>
        bool IList.Contains(object value)
        {
            return this.Contains((T)value);
        }

        /// <summary>
        /// Determines the index of a specific item in the <see cref="T:System.Collections.IList"/>.
        /// </summary>
        /// <param name="value">
        /// The object to locate in the <see cref="T:System.Collections.IList"/>.
        /// </param>
        /// <returns>
        /// The index of <paramref name="value"/> if found in the list; otherwise, -1.
        /// </returns>
        int IList.IndexOf(object value)
        {
            return this.IndexOf((T)value);
        }

        /// <summary>
        /// Inserts an item to the <see cref="T:System.Collections.IList"/> at the specified index.
        /// </summary>
        /// <param name="index">
        /// The zero-based index at which <paramref name="value"/> should be inserted.
        /// </param>
        /// <param name="value">
        /// The object to insert into the <see cref="T:System.Collections.IList"/>.
        /// </param>
        void IList.Insert(int index, object value)
        {
            this.Insert(index, (T)value);
        }

        /// <summary>
        /// Gets a value indicating whether the <see cref="T:System.Collections.IList" /> has a fixed size.
        /// </summary>
        bool IList.IsFixedSize
        {
            get
            {
                return this.adaptedList is Array;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is read only.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is read only; otherwise, <c>false</c>.
        /// </value>
        bool IList.IsReadOnly
        {
            get { return this.IsReadOnly; }
        }

        /// <summary>
        /// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.IList"/>.
        /// </summary>
        /// <param name="value">
        /// The object to remove from the <see cref="T:System.Collections.IList"/>.
        /// </param>
        void IList.Remove(object value)
        {
            this.Remove((T)value);
        }

        /// <summary>
        /// Removes the <see cref="T:System.Collections.Generic.IList`1"/> item at the specified index.
        /// </summary>
        /// <param name="index">
        /// The zero-based index of the item to remove.
        /// </param>
        void IList.RemoveAt(int index)
        {
            this.RemoveAt(index);
        }

        /// <summary>
        /// Gets or sets the element at the specified index.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <returns>
        /// The <see cref="object"/>.
        /// </returns>
        object IList.this[int index]
        {
            get
            {
                return this[index];
            }

            set
            {
                this[index] = (T)value;
            }
        }

        /// <summary>
        /// Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
        /// </summary>
        /// <param name="array">
        /// The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.ICollection"/>. The <see cref="T:System.Array"/> must have zero-based indexing.
        /// </param>
        /// <param name="index">
        /// The zero-based index in <paramref name="array"/> at which copying begins.
        /// </param>
        void ICollection.CopyTo(Array array, int index)
        {
            this.CopyTo((T[])array, index);
        }

        /// <summary>
        /// Gets the count.
        /// </summary>
        /// <value>
        /// The count.
        /// </value>
        int ICollection.Count
        {
            get
            {
                return this.Count;
            }
        }

        /// <summary>
        /// Gets a value indicating whether access to the <see cref="T:System.Collections.ICollection" /> is synchronized (thread safe).
        /// </summary>
        bool ICollection.IsSynchronized
        {
            get
            {
                var list = this.adaptedList as IList;
                if (list != null)
                {
                    return list.IsSynchronized;
                }

                return false;
            }
        }

        /// <summary>
        /// Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection" />.
        /// </summary>
        object ICollection.SyncRoot
        {
            get
            {
                var list = this.adaptedList as IList;
                if (list != null)
                {
                    return list.SyncRoot;
                }

                return null;
            }
        }

        /// <summary>
        /// Gets the enumerator.
        /// </summary>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion IList Members
    }
}
